/*
Copyright (c) 2008, Daniel Guerrero Martínez
All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
	-Redistributions of source code must retain the above copyright notice, this
	list of conditions and the following disclaimer.
	-Redistributions in binary form must reproduce the above copyright notice,
	this list of conditions and the following disclaimer in the documentation
	and/or other materials provided with the distribution.
	-Neither the name of the <ORGANIZATION> nor the names of its contributors may
	be used to endorse or promote products derived from this software without
	specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
 */


package Imagenes;

import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Point;
import java.awt.Stroke;
import java.awt.geom.AffineTransform;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.QuadCurve2D;
import java.awt.geom.Rectangle2D;

abstract class Figura {
    public static final char TIPO_LINEA = 'l';
    public static final char TIPO_RECTANGULO = 'r';
    public static final char TIPO_CIRCULO = 'c';
    public static final char TIPO_MOVER = 'm';
    public static final char TIPO_CURVA = 'q';
    public static final char TIPO_CURVA_2C = 'Q';
    public static final char TIPO_TEXTO = 't';
    public static final char TIPO_TRAZO = 'T';


  abstract void Dibujar(Graphics2D G);
  abstract void Elastico(Point2D X);
  abstract boolean es_figura(Point X);
  abstract Rectangle2D rec_contenedor();
  abstract char getTipoFigura();
  abstract void mover(int incX, int incY);
}





class Curva extends Figura{
    protected QuadCurve2D curva;
    protected Stroke stroke;
    protected Paint paint;
    private AlphaComposite alfa;


    Curva(Point2D inicio, Point2D fin, Point2D control, Stroke S, Paint P, AlphaComposite A){
        curva = new QuadCurve2D.Double(inicio.getX(), inicio.getY(), control.getX(), control.getY(), fin.getX(), fin.getY());
        stroke = S;
        paint = P;
        alfa = A;
    }

    Curva(Linea lin){
        curva = new QuadCurve2D.Double(lin.linea.getP1().getX(), lin.linea.getP1().getY(), lin.linea.getP2().getX(),lin.linea.getP2().getY() , lin.linea.getP2().getX(), lin.linea.getP2().getY());
        stroke = lin.stroke;
        paint = lin.paint;
        alfa = lin.alfa;
    }

    @Override
    void Dibujar(Graphics2D G) {
        G.setStroke(stroke);
        G.setPaint(paint);
        G.setComposite(alfa);
        G.draw(curva);
    }

    @Override
    void Elastico(Point2D X) {
        curva.setCurve(curva.getP1(), X, curva.getP2());
    }

    @Override
    boolean es_figura(Point X) {
        return curva.contains(X);
    }

    @Override
    Rectangle2D rec_contenedor() {
        return curva.getBounds2D();
    }

    char getTipoFigura(){
        return Figura.TIPO_CURVA;
    }

    void mover(int incX, int incY){
        curva.setCurve(curva.getX1()+incX, curva.getY1()+incY, curva.getCtrlX()+incX, curva.getCtrlY()+incY, curva.getX2()+incX, curva.getY2()+incY);
    }

}

class Curva_2C extends Figura{
    private CubicCurve2D curva;
    private Stroke stroke;
    private Paint paint;
    private AlphaComposite alfa;


    Curva_2C(Point2D inicio, Point2D fin, Point2D control, Point2D control2, Stroke S, Paint P, AlphaComposite A){
        curva = new CubicCurve2D.Double(inicio.getX(), inicio.getY(), control.getX(), control.getY(), control2.getX(), control2.getY() , fin.getX(), fin.getY());
        stroke = S;
        paint = P;
        alfa = A;
    }


    @Override
    void Dibujar(Graphics2D G) {
        G.setStroke(stroke);
        G.setPaint(paint);
        G.setComposite(alfa);
        G.draw(curva);
    }

    @Override
    void Elastico(Point2D X) {
        curva.setCurve(curva.getP1(), X,X, X);
    }

    void Mod_1P_control(Point2D X){
        curva.setCurve(curva.getP1(), X,curva.getCtrlP2(), curva.getP2());
    }

    void Mod_2P_control(Point2D X){
        curva.setCurve(curva.getP1(), curva.getCtrlP1(),X, curva.getP2());
    }

    @Override
    boolean es_figura(Point X) {
        return curva.contains(X);
    }

    @Override
    Rectangle2D rec_contenedor() {
        return curva.getBounds2D();
    }

    char getTipoFigura(){
        return Figura.TIPO_CURVA_2C;
    }

    void mover(int incX, int incY){
        curva.setCurve(curva.getX1()+incX, curva.getY1()+incY, curva.getCtrlX1()+incX, curva.getCtrlY1()+incY, curva.getCtrlX2()+incX, curva.getCtrlY2()+incY
                , curva.getX2()+incX, curva.getY2()+incY);
    }

}





class Trazo extends Figura{

  Stroke stroke;
  Paint paint;
  private AlphaComposite alfa;
  java.awt.geom.GeneralPath lista;

  Trazo(Point2D X, Stroke S, Paint P, AlphaComposite A){
    stroke = S;
    paint = P;
    lista = new java.awt.geom.GeneralPath(new java.awt.geom.Line2D.Double(X, X));
    alfa = A;
    lista.lineTo(X.getX(), X.getY());
  }

    @Override
  public void Dibujar(Graphics2D G ){
        G.setStroke(stroke);
        G.setPaint(paint);
        G.setComposite(alfa);
        G.draw(lista);
  }

    @Override
  public void Elastico(Point2D X){
        lista.lineTo(X.getX(), X.getY());
  }

    @Override
    boolean es_figura(Point X) {
        return lista.contains(X);
    }

    @Override
    Rectangle2D rec_contenedor() {
        return lista.getBounds2D();
    }

    char getTipoFigura(){
        return Figura.TIPO_TRAZO;
    }

    @Override
    void mover(int incX, int incY) {
        AffineTransform at = AffineTransform.getTranslateInstance(incX, incY);
        lista.transform(at);
    }

}
class Linea extends Figura{
  protected Line2D linea;
  Stroke stroke;
  Paint paint;
  AlphaComposite alfa;

  Linea(Point2D X, Point2D Y, Stroke S, Paint P,AlphaComposite A){
    linea = new Line2D.Float(X, Y);
    stroke = S;
    paint = P;
    alfa = A;
  }

    @Override
  public void Dibujar(Graphics2D G){
    G.setStroke(stroke);
    G.setPaint(paint);
    G.setComposite(alfa);
    G.draw(linea);
  }

    @Override
  public void Elastico(Point2D X){
    linea.setLine(linea.getP1(), X);
  }

    @Override
    boolean es_figura(Point X) {
        return linea.getBounds2D().contains(X);
    }

    @Override
    Rectangle2D rec_contenedor() {
        return linea.getBounds2D();
    }

    char getTipoFigura(){
        return Figura.TIPO_LINEA;
    }

    void mover(int incX, int incY){
        linea.setLine(linea.getX1()+incX, linea.getY1()+incY, linea.getX2()+incX, linea.getY2()+incY);
    }
}


class Circulo extends Figura{
  private Ellipse2D circulo;
  private Point2D C;
  private Stroke stroke;
  private Paint paint;
  private boolean relleno;
  private AlphaComposite alfa;


  public Circulo(Point2D X, Point2D Y, Stroke S,Paint P,boolean R, AlphaComposite A){
      stroke = S;
      paint = P;
      double dis = X.distance(Y);
      C = X;
      relleno = R;
      alfa = A;
      circulo = new Ellipse2D.Float((int)(X.getX()-(dis)),(int)(X.getY()-(dis)),(int)(2*dis),(int)(2*dis));
  }

  public void Dibujar(Graphics2D G){
    G.setStroke(stroke);
    G.setPaint(paint);
    G.setComposite(alfa);
    if(relleno)
        G.fill(circulo);
    else
        G.draw(circulo);
  }

  public void Elastico(Point2D X){
    Point2D punto = new Point2D.Double(circulo.getX(), circulo.getY());
    double dis = C.distance(X);
    circulo.setFrame(C.getX()-dis, C.getY()-dis, dis*2, dis*2);
  }

    @Override
    boolean es_figura(Point X) {
        return circulo.contains(X);
    }

    @Override
    Rectangle2D rec_contenedor() {
        return circulo.getFrame();
    }

    char getTipoFigura(){
        return Figura.TIPO_CIRCULO;
    }

    void mover(int incX, int incY){
        circulo.setFrame(circulo.getX()+incX, circulo.getY()+incY, circulo.getWidth(), circulo.getHeight());
    }


}




class Rectangulo extends Figura{
    private Stroke stroke;
    private Rectangle2D rec;
    private Point2D Aizq;
    private double ancho;
    private double alto;
    private Paint paint;
    private boolean relleno;
    private AlphaComposite alfa;

  Rectangulo(Point2D X, Point2D Y,Stroke S,Paint P,boolean R,AlphaComposite A){
      stroke = S;
      paint = P;
      Aizq = X;
      alfa = A;
      ancho = Y.getX()-X.getX();
      alto = Y.getY()-Y.getY();
      relleno = R;
      rec = new Rectangle2D.Double(Aizq.getX(), Aizq.getY(), ancho, alto);
  }

    @Override
  public void Dibujar(Graphics2D G){
        G.setStroke(stroke);
        G.setPaint(paint);
        G.setComposite(alfa);
        if(relleno)
            G.fill(rec);
        else
            G.draw(rec);

     
  }

  public void Elastico(Point2D X){

    if(Aizq.getX()>X.getX())
      if(Aizq.getY()>X.getY()){
          ancho=Aizq.getX()-X.getX();
          alto = Aizq.getY()-X.getY();
          rec.setRect(X.getX(), X.getY(), ancho, alto);
      }else{
          ancho=Aizq.getX()-X.getX();
          alto = X.getY()-Aizq.getY();
          rec.setRect(X.getX(), Aizq.getY(), ancho, alto);
      }
    else
      if(Aizq.getY()>X.getY()){
          ancho=X.getX()-Aizq.getX();
          alto = Aizq.getY()-X.getY();
          rec.setRect(Aizq.getX(), X.getY(), ancho, alto);
      }else{
          ancho=X.getX()-Aizq.getX();
          alto = X.getY()-Aizq.getY();
          rec.setRect(Aizq.getX(), Aizq.getY(), ancho, alto);
      }
  }

    @Override
    boolean es_figura(Point X) {
        return rec.contains(X);
    }

    @Override
    Rectangle2D rec_contenedor() {
        return rec.getFrame();
    }

    char getTipoFigura(){
        return Figura.TIPO_RECTANGULO;
    }

    void mover(int incX, int incY){
        rec.setRect(rec.getX()+incX, rec.getY()+incY, rec.getWidth(),rec.getHeight());
    }

}



class Texto extends Figura{
    Point2D pos;
    private String texto;
    Stroke stroke;
    Paint paint;
    Font fuente;

    Texto(Point2D X,String t, Font fu,Stroke S,Paint P){
        pos = X;
        texto = t;
        stroke = S;
        paint = P;
        fuente = fu;
    }

    static Texto CrearTexto(java.awt.Frame padre,Point2D X,BarraHerramientas H){
        DialogoNuevoTexto dialogo = new DialogoNuevoTexto(padre,true,H, X);
        return dialogo.getTexto();
    }

    static Texto ModificarTexto(java.awt.Frame padre,Texto txt){
        DialogoNuevoTexto dialogo = new DialogoNuevoTexto(padre,true,txt);
        return dialogo.getTexto();
    }

    String getTexto(){
        return this.texto;
    }

    void setTexto(String str){
        texto = str;
    }

    @Override
    void Dibujar(Graphics2D G) {
        G.setStroke(stroke);
        G.setPaint(paint);
        G.setFont(fuente);
        G.drawString(texto,(int) pos.getX(),(int) pos.getY());
    }

    @Override
    void Elastico(Point2D X) {

    }

    @Override
    boolean es_figura(Point X) {
        double relativo_ancho =  X.getX() - pos.getX() ;
        double relativo_alto =  pos.getY() - X.getY();
        if(relativo_ancho>=0 && relativo_alto>=0)
            if(relativo_ancho<=fuente.getSize()*texto.length() && relativo_alto<=fuente.getSize())
                return true;
        return false;
    }

    @Override
    Rectangle2D rec_contenedor() {
        return new Rectangle2D.Double(pos.getX(), pos.getY()-fuente.getSize(),(fuente.getSize()*texto.length()) , fuente.getSize());
    }

    char getTipoFigura(){
        return Figura.TIPO_TEXTO;
    }

    void mover(int incX, int incY){
        pos.setLocation(pos.getX()+incX, pos.getY()+incY);
    }


    private static class DialogoNuevoTexto extends javax.swing.JDialog {

      
        public DialogoNuevoTexto(java.awt.Frame parent, boolean modal,Texto txt) {
            super(parent, modal);
            initComponents();
            texto = txt;
            pos = txt.pos;
            B_text.setText(txt.getTexto());
            B_tama.setValue(txt.fuente.getSize());
            stroke = txt.stroke;
            paint = txt.paint;
            if(txt.fuente.isBold())
                B_negrita.setSelected(true);
            if(txt.fuente.isItalic())
                B_cursiva.setSelected(true);
            CB_fuentes.setSelectedItem(txt.fuente.getFontName());
            this.setVisible(true);
        }


        public DialogoNuevoTexto(java.awt.Frame parent, boolean modal,BarraHerramientas H, Point2D P) {
            super(parent, modal);
            initComponents();
            stroke = H.stroke;
            paint = H.paint;
            pos = P;
            texto = null;
            this.setVisible(true);
        }

        private void initComponents() {

            E_text = new javax.swing.JLabel();
            B_text = new javax.swing.JTextField();
            CB_fuentes = new javax.swing.JComboBox();
            E_tipo = new javax.swing.JLabel();
            B_negrita = new javax.swing.JRadioButton();
            B_cursiva = new javax.swing.JRadioButton();
            B_aceptar = new javax.swing.JButton();
            B_cancelar = new javax.swing.JButton();
            B_tama = new javax.swing.JSpinner();
            E_tama = new javax.swing.JLabel();

            FormListener formListener = new FormListener();

            setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
            setMinimumSize(new java.awt.Dimension(600, 200));
            setResizable(false);
            getContentPane().setLayout(null);

            E_text.setText("Introduce el texto:");
            getContentPane().add(E_text);
            E_text.setBounds(20, 3, 180, 20);
            getContentPane().add(B_text);
            B_text.setBounds(20, 23, 480, 30);

            CB_fuentes.setModel(new javax.swing.DefaultComboBoxModel(java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames()));
            getContentPane().add(CB_fuentes);
            CB_fuentes.setBounds(20, 90, 140, 23);

            E_tipo.setText("Tipo de letra");
            getContentPane().add(E_tipo);
            E_tipo.setBounds(20, 63, 100, 20);

            B_negrita.setText("Negrita");
            getContentPane().add(B_negrita);
            B_negrita.setBounds(180, 80, 110, 22);

            B_cursiva.setText("Cursiva");
            getContentPane().add(B_cursiva);
            B_cursiva.setBounds(180, 110, 120, 22);

            B_aceptar.setText("Aceptar");
            B_aceptar.addActionListener(formListener);
            getContentPane().add(B_aceptar);
            B_aceptar.setBounds(280, 120, 110, 25);

            B_cancelar.setText("Cancelar");
            B_cancelar.addActionListener(formListener);
            getContentPane().add(B_cancelar);
            B_cancelar.setBounds(400, 120, 110, 25);

            B_tama.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(12), null, null, Integer.valueOf(1)));
            getContentPane().add(B_tama);
            B_tama.setBounds(330, 70, 60, 24);

            E_tama.setText("Tamaño:");
            getContentPane().add(E_tama);
            E_tama.setBounds(280, 70, 50, 20);

            pack();
        }


        private class FormListener implements java.awt.event.ActionListener {
            FormListener() {}
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                if (evt.getSource() == B_aceptar) {
                    DialogoNuevoTexto.this.nuevo_texto(evt);
                }
                else if (evt.getSource() == B_cancelar) {
                    DialogoNuevoTexto.this.Cancelartexto(evt);
                }
            }
        }

        private void nuevo_texto(java.awt.event.ActionEvent evt) {

            if(B_negrita.isSelected() && B_cursiva.isSelected())
                texto = new Texto(pos,B_text.getText(),new Font((String)CB_fuentes.getSelectedItem(), Font.BOLD | Font.ITALIC,(Integer)B_tama.getValue()),stroke,paint);
            else if(B_negrita.isSelected())
                texto = new Texto(pos,B_text.getText(),new Font((String)CB_fuentes.getSelectedItem(), Font.BOLD ,(Integer)B_tama.getValue()),stroke,paint);
                else if(B_cursiva.isSelected())
                    texto = new Texto(pos,B_text.getText(),new Font((String)CB_fuentes.getSelectedItem(), Font.ITALIC ,(Integer)B_tama.getValue()),stroke,paint);
                    else
                        texto = new Texto(pos,B_text.getText(),new Font((String)CB_fuentes.getSelectedItem(), Font.PLAIN ,(Integer)B_tama.getValue()),stroke,paint);

            System.out.print("estamos confirmando en nuevo texto");
            this.setVisible(false);
        }

        private void Cancelartexto(java.awt.event.ActionEvent evt) {
            this.setVisible(false);
        }



        public Texto getTexto(){
            return texto;
        }

        private javax.swing.JButton B_aceptar;
        private javax.swing.JButton B_cancelar;
        private javax.swing.JRadioButton B_cursiva;
        private javax.swing.JRadioButton B_negrita;
        private javax.swing.JSpinner B_tama;
        private javax.swing.JTextField B_text;
        private javax.swing.JComboBox CB_fuentes;
        private javax.swing.JLabel E_tama;
        private javax.swing.JLabel E_text;
        private javax.swing.JLabel E_tipo;
        Texto texto;
        Stroke stroke;
        Paint paint;
        Point2D pos;
    }




}

